#pragma once
namespace graph
{
   namespace details
   {
      //graph_base_t
      inline graph_id_t graph_base_t::get_graph_id() const
      {
         return inf_.id_;
      }
      inline size_t graph_base_t::get_vertex_count() const
      {
         return inf_.vertex_count_;
      }
      inline size_t graph_base_t::get_edge_count() const
      {
         return inf_.edge_count_;
      }
      inline lat_lon_t graph_base_t::get_min_lat() const
      {
         return inf_.min_lat_;
      }
      inline lat_lon_t graph_base_t::get_min_lon() const
      {
         return inf_.min_lon_;
      }
      inline lat_lon_t graph_base_t::get_max_lat() const
      {
         return inf_.max_lat_;
      }
      inline lat_lon_t graph_base_t::get_max_lon() const
      {
         return inf_.max_lon_;
      } 

      //graph_sequential_t
      inline vertex_t const & graph_sequential_t::operator [] (size_t idx) const
      {
         return *(reinterpret_cast<vertex_t*>( const_cast<char(*)[0]>(&data_) ) + idx);
         //*(reinterpret_cast<const vertex_t*>(reinterpret_cast<char* const*>(&data_)) + idx); 
      }

      inline vertex_t& graph_sequential_t::operator [] (size_t idx)
      {
         return *(reinterpret_cast<vertex_t*>( const_cast<char(*)[0]>(&data_) ) + idx);
      }

      inline vertex_t const & graph_sequential_t::get_vertex_by_id(size_t idx) const
      {
         return (*this)[idx];
      }

      inline vertex_t & graph_sequential_t::get_vertex_by_id(size_t idx)
      {
         return (*this)[idx];
      }
      //TODO const const
      inline std::pair<details::edge_real_t*, details::edge_real_t*> 
         graph_sequential_t::get_vertex_edges(vertex_in_graph_id_t idx) const
      {        
         return std::make_pair(
            begin_of_edges_ + (*this)[idx].get_adj_list_offset(),
            (
               idx + 1 != inf_.vertex_count_ 
               ?  begin_of_edges_ + (*this)[idx + 1].get_adj_list_offset()
               :  begin_of_edges_ + inf_.edge_count_
            )
         );
      }   
      
      inline std::pair<details::edge_real_t*, details::edge_real_t*> 
         graph_sequential_t::get_vertex_in_edges(vertex_in_graph_id_t idx) const
      {
         return std::make_pair(
            begin_of_in_edges_ + (*this)[idx].get_adj_in_list_offset(),
            (
               idx + 1 != inf_.vertex_count_ 
               ?  begin_of_in_edges_ + (*this)[idx + 1].get_adj_in_list_offset()
               :  begin_of_in_edges_ + inf_.edge_count_
            )
         );
      }

      inline void graph_sequential_t::load_from_file
               (std::string file_name, graph_sequential_t** result, details::graph_finalizer_ptr_t& finalizer)
      {
         details::mapped_file_ptr_t m_file = details::mapped_file_ptr_t(
            new boost::interprocess::file_mapping(file_name.c_str(), boost::interprocess::read_write)
         );
         details::mapped_region_ptr_t region = details::mapped_region_ptr_t(
            new boost::interprocess::mapped_region(*m_file.get(), boost::interprocess::read_write, 0, 0)
         );

         *result = reinterpret_cast<graph_sequential_t*>(region->get_address());
         finalizer = details::graph_finalizer_ptr_t(new details::graph_finalizer_t(*result, m_file, region));
         (*result)->begin_of_edges_ = reinterpret_cast<details::edge_real_t*>(
                  reinterpret_cast<vertex_t*>( const_cast<char(*)[0]>(&(*result)->data_) ) + (*result)->inf_.vertex_count_
               );
         (*result)->begin_of_in_edges_ = (*result)->begin_of_edges_ + (*result)->get_edge_count();
      }
      //graph_not_sequential_t
      inline vertex_t const & graph_not_sequential_t::operator [] (size_t idx) const
      {
         return vertices_[idx];
      }   

      inline vertex_t& graph_not_sequential_t::operator [] (size_t idx) 
      {
         return vertices_[idx];
      }

      inline vertex_t const & graph_not_sequential_t::get_vertex_by_id(size_t idx) const
      {
         return (*this)[idx];
      }

      inline vertex_t & graph_not_sequential_t::get_vertex_by_id(size_t idx)
      {
         return (*this)[idx];
      }

      inline std::pair<details::edge_real_t*, details::edge_real_t*> graph_not_sequential_t::get_vertex_edges(vertex_in_graph_id_t idx) const
      {     
         return std::make_pair(
            edges_ + (*this)[idx].get_adj_list_offset(),
            (
               idx + 1 != inf_.vertex_count_ 
               ?  edges_ + (*this)[idx + 1].get_adj_list_offset()
               :  edges_ + inf_.edge_count_
            )
         );
      }   

      inline void graph_not_sequential_t::load_from_file
              (std::string file_name, graph_not_sequential_t** result, details::graph_finalizer_ptr_t& finalizer)
      {      
         throw graph_exception_t("not implemented");
      }
   }
   
}
